package cn.itsource.org.config;

import cn.hutool.core.util.StrUtil;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
 
/**
 * @Class_Name: MybatisInterceptor
 * @author: maizi
 * @Description: 自定义mybatis的拦截器
 * @Date: 16:21 2022/3/1
 */
 
//拦截StatementHandler类中参数类型为Statement的 prepare 方法
//即拦截 Statement prepare(Connection var1, Integer var2) 方法
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MybatisInterceptor implements Interceptor {
 
    //拦截器
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
 
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        //通过MetaObject优雅访问对象的属性，这里是访问statementHandler的属性;：MetaObject是Mybatis提供的一个用于方便、
        //优雅访问对象属性的对象，通过它可以简化代码、不需要try/catch各种reflect异常，同时它支持对JavaBean、Collection、Map三种类型对象的操作。
        MetaObject metaObject = MetaObject
            .forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                new DefaultReflectorFactory());
        //先拦截到RoutingStatementHandler，里面有个StatementHandler类型的delegate变量，其实现类是BaseStatementHandler，然后就到BaseStatementHandler的成员变量mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        //id为执行的mapper方法的全路径名，如com.uv.dao.UserMapper.insertUser
        String id = mappedStatement.getId();
        //sql语句类型 select、delete、insert、update
        String sqlCommandType = mappedStatement.getSqlCommandType().toString();
        // 仅拦截 select 查询
        if (!sqlCommandType.equals(SqlCommandType.SELECT.toString())) {
            return invocation.proceed();
        }
        //数据库连接信息
//        Configuration configuration = mappedStatement.getConfiguration();
//        ComboPooledDataSource dataSource = (ComboPooledDataSource)configuration.getEnvironment().getDataSource();
//        dataSource.getJdbcUrl();
        BoundSql boundSql = statementHandler.getBoundSql();
        //获取到原始sql语句  select * from t_department
        String sql = boundSql.getSql();
        //获取表名
      //  String tableName = sql.substring(sql.indexOf("from") , sql.indexOf("where"));
        sql = sql.toLowerCase ();
        String mSql = null;
        String del = " and del = 1 ";

        if (sql.contains("td1")){
            del = " and td1.del = 1 ";
        }
        if(!sql.contains ("where")){
            //这里做的sql拼接  select * from t_department  where  del = 1
            del = " where "+del.replace ("and","");
        }

        //如果有分页
        if(sql.contains ("limit") ){
            //在分页前插入  select * from t_department   where 1=1  and del = 1 del = 1 limit 0 ,10
            mSql = replacementInfo (new StringBuilder (sql), "limit", del, "");
        }else {
             mSql = sql + del;
        }

        //如果调用了返回主键的 sql SELECT LAST_INSERT_ID()
        if (StrUtil.containsIgnoreCase(sql,"SELECT LAST_INSERT_ID()")){
            mSql = sql;
        }

        //通过反射修改sql语句
        Field field = boundSql.getClass().getDeclaredField("sql");
        field.setAccessible(true);
        field.set(boundSql, mSql);
        //继续执行
        return invocation.proceed();
    }
    /**
     * 在某字符前后添加字段
     * @param stringBuilder：原字符串
     * @param keyword：字符
     * @param before：在字符前需要插入的字段
     * @param rear：在字符后需要插入的字段
     * @return
     */
    public static String replacementInfo(StringBuilder stringBuilder, String keyword, String before, String rear) {
        //字符第一次出现的位置

        int index = stringBuilder.indexOf (keyword);
        if (index != -1) {
            stringBuilder.insert (index, before);
            stringBuilder.insert (index + before.length () + keyword.length (), rear);
            //下一次出现的位置，
            //index = stringBuilder.indexOf (keyword, index + before.length () + keyword.length () + rear.length () - 1);
        }
        return stringBuilder.toString ();

    }
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
 
    @Override
    public void setProperties(Properties properties) {
        //此处可以接收到配置文件的property参数
        System.out.println(properties.getProperty("name"));
    }
 
}
